"""
用户仓储
========

用户数据访问层
"""

import uuid
from typing import List, Optional, Tuple, Callable
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select, func, or_

from ..models.user import User


class UserRepository:
    """用户仓储类"""
    
    def __init__(self, session_factory: Callable[[], AsyncSession]):
        """初始化仓储"""
        self.session_factory = session_factory
    
    async def create(self, user_data: dict) -> User:
        """创建用户"""
        async with self.session_factory() as session:
            user = User(
                id=str(uuid.uuid4()),
                **user_data
            )
            session.add(user)
            await session.commit()
            await session.refresh(user)
            return user
    
    async def get_by_id(self, user_id: str) -> Optional[User]:
        """根据ID获取用户"""
        async with self.session_factory() as session:
            stmt = select(User).where(User.id == user_id)
            result = await session.execute(stmt)
            return result.scalar_one_or_none()
    
    async def get_by_username(self, username: str) -> Optional[User]:
        """根据用户名获取用户"""
        async with self.session_factory() as session:
            stmt = select(User).where(User.username == username)
            result = await session.execute(stmt)
            return result.scalar_one_or_none()
    
    async def get_by_email(self, email: str) -> Optional[User]:
        """根据邮箱获取用户"""
        async with self.session_factory() as session:
            stmt = select(User).where(User.email == email)
            result = await session.execute(stmt)
            return result.scalar_one_or_none()
    
    async def update(self, user_id: str, **kwargs) -> Optional[User]:
        """更新用户"""
        async with self.session_factory() as session:
            user = await session.get(User, user_id)
            if not user:
                return None
            
            for key, value in kwargs.items():
                if hasattr(user, key):
                    setattr(user, key, value)
            
            await session.commit()
            await session.refresh(user)
            return user
    
    async def delete(self, user_id: str) -> bool:
        """删除用户"""
        async with self.session_factory() as session:
            user = await session.get(User, user_id)
            if not user:
                return False
            
            await session.delete(user)
            await session.commit()
            return True
    
    async def list(
        self,
        skip: int = 0,
        limit: int = 20,
        search: Optional[str] = None
    ) -> Tuple[List[User], int]:
        """获取用户列表"""
        async with self.session_factory() as session:
            # 构建查询
            query = select(User)
            count_query = select(func.count(User.id))
            
            # 添加搜索条件
            if search:
                search_filter = or_(
                    User.username.ilike(f"%{search}%"),
                    User.email.ilike(f"%{search}%")
                )
                query = query.where(search_filter)
                count_query = count_query.where(search_filter)
            
            # 获取总数
            count_result = await session.execute(count_query)
            total = count_result.scalar()
            
            # 获取用户列表
            query = query.order_by(User.created_at.desc()).offset(skip).limit(limit)
            result = await session.execute(query)
            users = result.scalars().all()
            
            return list(users), total
    
    async def exists_by_username(self, username: str) -> bool:
        """检查用户名是否存在"""
        user = await self.get_by_username(username)
        return user is not None
    
    async def exists_by_email(self, email: str) -> bool:
        """检查邮箱是否存在"""
        user = await self.get_by_email(email)
        return user is not None
    
    async def exists_by_username_exclude_id(self, username: str, user_id: str) -> bool:
        """检查用户名是否存在（排除指定ID）"""
        async with self.session_factory() as session:
            stmt = select(User).where(
                User.username == username,
                User.id != user_id
            )
            result = await session.execute(stmt)
            return result.scalar_one_or_none() is not None
    
    async def exists_by_email_exclude_id(self, email: str, user_id: str) -> bool:
        """检查邮箱是否存在（排除指定ID）"""
        async with self.session_factory() as session:
            stmt = select(User).where(
                User.email == email,
                User.id != user_id
            )
            result = await session.execute(stmt)
            return result.scalar_one_or_none() is not None
    
    # 事务支持方法
    async def create_with_session(self, session: AsyncSession, user_data: dict) -> User:
        """在指定会话中创建用户（用于事务）"""
        user = User(
            id=str(uuid.uuid4()),
            **user_data
        )
        session.add(user)
        return user